```html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Guava RateLimiter 深度解析</title>
    <link href="https://cdn.staticfile.org/font-awesome/6.4.0/css/all.min.css" rel="stylesheet">
    <link href="https://cdn.staticfile.org/tailwindcss/2.2.19/tailwind.min.css" rel="stylesheet">
    <link href="https://fonts.googleapis.com/css2?family=Noto+Serif+SC:wght@400;500;600;700&family=Noto+Sans+SC:wght@300;400;500;700&display=swap" rel="stylesheet">
    <style>
        body {
            font-family: 'Noto Sans SC', Tahoma, Arial, Roboto, "Droid Sans", "Helvetica Neue", "Droid Sans Fallback", "Heiti SC", "Hiragino Sans GB", Simsun, sans-serif;
            color: #333;
            line-height: 1.8;
        }
        .hero-title {
            font-family: 'Noto Serif SC', serif;
            text-shadow: 0 2px 4px rgba(0,0,0,0.1);
        }
        .article-content {
            max-width: 900px;
        }
        .section-title {
            position: relative;
            padding-left: 1.5rem;
        }
        .section-title:before {
            content: '';
            position: absolute;
            left: 0;
            top: 0.5em;
            height: 1.2em;
            width: 4px;
            background: linear-gradient(to bottom, #3B82F6, #10B981);
            border-radius: 2px;
        }
        .code-block {
            background: #2D3748;
            border-radius: 0.5rem;
            box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
        }
        .code-block pre {
            font-family: 'Menlo', 'Monaco', 'Courier New', monospace;
            tab-size: 4;
        }
        .compare-table {
            border-collapse: separate;
            border-spacing: 0;
        }
        .compare-table th, .compare-table td {
            border-bottom: 1px solid #E5E7EB;
            padding: 0.75rem 1rem;
        }
        .compare-table th {
            background-color: #F9FAFB;
            font-weight: 600;
        }
        .compare-table tr:hover td {
            background-color: #F3F4F6;
        }
        .highlight-card {
            transition: all 0.3s ease;
            border-left: 4px solid #3B82F6;
        }
        .highlight-card:hover {
            transform: translateY(-2px);
            box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
        }
        .token-bucket {
            width: 200px;
            height: 300px;
            position: relative;
            background: #EFF6FF;
            border-radius: 0.5rem;
            overflow: hidden;
        }
        .tokens {
            position: absolute;
            bottom: 0;
            width: 100%;
            background: #3B82F6;
            transition: height 1s ease;
        }
        .token {
            display: inline-block;
            width: 16px;
            height: 16px;
            background: white;
            border-radius: 50%;
            margin: 2px;
        }
    </style>
</head>
<body class="bg-gray-50">
    <!-- Hero Section -->
    <section class="relative bg-gradient-to-r from-blue-600 to-blue-400 text-white py-20 md:py-32 px-4">
        <div class="max-w-6xl mx-auto text-center">
            <div class="mb-6 inline-block px-4 py-2 bg-white bg-opacity-20 rounded-full backdrop-filter backdrop-blur-sm">
                <span class="text-sm font-medium">高并发系统设计</span>
            </div>
            <h1 class="hero-title text-4xl md:text-6xl font-bold mb-6 leading-tight">
                Guava RateLimiter 深度解析
            </h1>
            <p class="text-xl md:text-2xl max-w-3xl mx-auto opacity-90 mb-8">
                揭秘令牌桶算法的精妙实现，打造稳定可靠的高并发系统
            </p>
            <div class="flex justify-center space-x-4">
                <a href="#content" class="px-8 py-3 bg-white text-blue-600 font-medium rounded-full hover:bg-blue-50 transition duration-300 transform hover:-translate-y-1">
                    <i class="fas fa-book-open mr-2"></i>开始阅读
                </a>
                <a href="#code-example" class="px-8 py-3 bg-transparent border-2 border-white text-white font-medium rounded-full hover:bg-white hover:bg-opacity-10 transition duration-300 transform hover:-translate-y-1">
                    <i class="fas fa-code mr-2"></i>代码示例
                </a>
            </div>
        </div>
        <div class="absolute bottom-0 left-0 right-0 h-16 bg-gradient-to-t from-gray-50 to-transparent"></div>
    </section>

    <!-- Main Content -->
    <main class="max-w-6xl mx-auto px-4 py-12 md:py-16">
        <article class="article-content mx-auto">
            <!-- Introduction -->
            <section class="mb-16">
                <div class="flex items-center mb-6">
                    <div class="h-px bg-gradient-to-r from-blue-400 to-transparent w-16"></div>
                    <span class="text-blue-600 font-medium ml-4">前言</span>
                </div>
                <p class="text-lg text-gray-700 mb-6 leading-relaxed">
                    在高并发系统中，限流就像高速公路上的红绿灯，没它你可能短时间内跑得很快，但最终会因为拥堵而寸步难行。我用过不少限流框架，但Guava的RateLimiter凭借其简单而强大的API，成了我工作中的常客。今天，咱们就扒一扒它的内部实现。
                </p>
                <div class="bg-blue-50 border-l-4 border-blue-500 p-4 rounded-r-lg mb-8">
                    <div class="flex">
                        <div class="flex-shrink-0">
                            <i class="fas fa-info-circle text-blue-500 mt-1"></i>
                        </div>
                        <div class="ml-3">
                            <p class="text-sm text-blue-700">
                                <span class="font-semibold">关键点：</span> RateLimiter 是 Google Guava 库中提供的限流工具，基于令牌桶算法实现，支持平滑限流和预热机制。
                            </p>
                        </div>
                    </div>
                </div>
            </section>

            <!-- 1. 令牌桶算法实现原理 -->
            <section class="mb-16">
                <h2 id="content" class="text-3xl font-bold text-gray-900 mb-8 section-title">1. 令牌桶算法实现原理</h2>
                
                <!-- 1.1 限流的必要性 -->
                <div class="mb-12">
                    <h3 class="text-2xl font-semibold text-gray-800 mb-4">1.1 限流的必要性</h3>
                    <p class="text-gray-700 mb-6">
                        为什么需要限流？这个问题看似简单，但答案却涉及系统稳定性的方方面面：
                    </p>
                    <div class="grid md:grid-cols-2 gap-6 mb-8">
                        <div class="highlight-card bg-white p-6 rounded-lg shadow-sm">
                            <div class="flex items-center mb-4">
                                <div class="w-10 h-10 rounded-full bg-blue-100 flex items-center justify-center mr-4">
                                    <i class="fas fa-shield-alt text-blue-600"></i>
                                </div>
                                <h4 class="text-lg font-semibold text-gray-800">防止系统过载</h4>
                            </div>
                            <p class="text-gray-600">系统资源总是有限的，限流可以确保在资源不足时优雅降级而非崩溃。</p>
                        </div>
                        <div class="highlight-card bg-white p-6 rounded-lg shadow-sm">
                            <div class="flex items-center mb-4">
                                <div class="w-10 h-10 rounded-full bg-green-100 flex items-center justify-center mr-4">
                                    <i class="fas fa-snowflake text-green-600"></i>
                                </div>
                                <h4 class="text-lg font-semibold text-gray-800">防止连锁故障</h4>
                            </div>
                            <p class="text-gray-600">上游限流避免下游雪崩，保护整个系统的稳定性。</p>
                        </div>
                        <div class="highlight-card bg-white p-6 rounded-lg shadow-sm">
                            <div class="flex items-center mb-4">
                                <div class="w-10 h-10 rounded-full bg-purple-100 flex items-center justify-center mr-4">
                                    <i class="fas fa-chart-line text-purple-600"></i>
                                </div>
                                <h4 class="text-lg font-semibold text-gray-800">业务削峰平谷</h4>
                            </div>
                            <p class="text-gray-600">将突发流量分散到更长的时间处理，使系统负载更加平稳。</p>
                        </div>
                        <div class="highlight-card bg-white p-6 rounded-lg shadow-sm">
                            <div class="flex items-center mb-4">
                                <div class="w-10 h-10 rounded-full bg-red-100 flex items-center justify-center mr-4">
                                    <i class="fas fa-user-shield text-red-600"></i>
                                </div>
                                <h4 class="text-lg font-semibold text-gray-800">应对恶意攻击</h4>
                            </div>
                            <p class="text-gray-600">抵御DoS/DDoS攻击，保护系统免受恶意流量的冲击。</p>
                        </div>
                    </div>
                    <div class="bg-yellow-50 border-l-4 border-yellow-400 p-4 rounded-r-lg">
                        <div class="flex">
                            <div class="flex-shrink-0">
                                <i class="fas fa-exclamation-triangle text-yellow-500 mt-1"></i>
                            </div>
                            <div class="ml-3">
                                <p class="text-sm text-yellow-700">
                                    <span class="font-semibold">血的教训：</span> 我曾经维护过一个没有限流的API系统，正常情况下运行良好。但一次营销活动中，流量瞬间暴增10倍，数据库连接池迅速耗尽，连带影响了其他核心服务，最终整个平台都不可用了。这种血的教训告诉我：<span class="font-semibold">限流不是可选项，而是高并发系统的必选项</span>。
                                </p>
                            </div>
                        </div>
                    </div>
                </div>

                <!-- 1.2 限流算法概述 -->
                <div class="mb-12">
                    <h3 class="text-2xl font-semibold text-gray-800 mb-4">1.2 限流算法概述</h3>
                    <p class="text-gray-700 mb-6">
                        常见的限流算法有几种：
                    </p>
                    
                    <div class="flex flex-wrap -mx-4 mb-8">
                        <div class="w-full md:w-1/3 px-4 mb-6">
                            <div class="bg-white p-6 rounded-lg shadow-sm h-full">
                                <h4 class="text-lg font-semibold text-gray-800 mb-3">计数器算法</h4>
                                <p class="text-gray-600 mb-4">在固定时间窗口内限制请求数量</p>
                                <div class="flex justify-center py-2">
                                    <div class="inline-flex space-x-1">
                                        <span class="w-3 h-3 rounded-full bg-blue-500"></span>
                                        <span class="w-3 h-3 rounded-full bg-blue-500"></span>
                                        <span class="w-3 h-3 rounded-full bg-blue-500"></span>
                                        <span class="w-3 h-3 rounded-full bg-blue-500"></span>
                                        <span class="w-3 h-3 rounded-full bg-gray-300"></span>
                                    </div>
                                </div>
                                <p class="text-xs text-gray-500 text-center">窗口内允许4个请求</p>
                            </div>
                        </div>
                        <div class="w-full md:w-1/3 px-4 mb-6">
                            <div class="bg-white p-6 rounded-lg shadow-sm h-full">
                                <h4 class="text-lg font-semibold text-gray-800 mb-3">漏桶算法</h4>
                                <p class="text-gray-600 mb-4">请求先进入漏桶，以固定速率流出</p>
                                <div class="flex justify-center py-2">
                                    <div class="relative w-16 h-20 border-2 border-gray-300 rounded-b-lg rounded-t-full overflow-hidden">
                                        <div class="absolute bottom-0 left-0 right-0 bg-blue-500" style="height: 70%;"></div>
                                        <div class="absolute bottom-0 left-1/2 transform -translate-x-1/2 w-1 h-3 bg-gray-400"></div>
                                    </div>
                                </div>
                                <p class="text-xs text-gray-500 text-center">固定速率流出请求</p>
                            </div>
                        </div>
                        <div class="w-full md:w-1/3 px-4 mb-6">
                            <div class="bg-white p-6 rounded-lg shadow-sm h-full">
                                <h4 class="text-lg font-semibold text-gray-800 mb-3">令牌桶算法</h4>
                                <p class="text-gray-600 mb-4">以固定速率生成令牌，请求需要消耗令牌</p>
                                <div class="flex justify-center py-2">
                                    <div class="relative w-16 h-20 border-2 border-gray-300 rounded-lg overflow-hidden">
                                        <div class="absolute bottom-0 left-0 right-0 bg-blue-500" style="height: 60%;"></div>
                                        <div class="absolute top-0 left-1/2 transform -translate-x-1/2 w-1 h-3 bg-gray-400"></div>
                                    </div>
                                </div>
                                <p class="text-xs text-gray-500 text-center">令牌生成与消耗</p>
                            </div>
                        </div>
                    </div>
                    
                    <p class="text-gray-700 mb-4">
                        Guava的RateLimiter实现了令牌桶算法的变体。令牌桶算法的核心思想是：
                    </p>
                    <ul class="list-disc pl-6 mb-6 text-gray-700 space-y-2">
                        <li>系统以恒定速率向桶中放入令牌</li>
                        <li>请求需要获取令牌才能继续执行</li>
                        <li>如果桶中没有令牌，请求需要等待</li>
                        <li>桶满后，多余的令牌会被丢弃</li>
                    </ul>
                    <p class="text-gray-700">
                        这种算法的优势在于可以应对突发流量，同时保证长期平均速率不超过限制。
                    </p>
                    
                    <!-- Token Bucket Visualization -->
                    <div class="mt-8 flex flex-col md:flex-row items-center justify-between bg-white p-6 rounded-lg shadow-sm">
                        <div class="mb-6 md:mb-0 md:mr-6">
                            <h4 class="text-lg font-semibold text-gray-800 mb-3">令牌桶算法可视化</h4>
                            <p class="text-gray-600 mb-4">通过交互演示理解令牌桶的工作原理：</p>
                            <div class="flex space-x-4">
                                <button id="addTokenBtn" class="px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 transition">
                                    <i class="fas fa-plus mr-2"></i>添加令牌
                                </button>
                                <button id="consumeTokenBtn" class="px-4 py-2 bg-green-600 text-white rounded-md hover:bg-green-700 transition">
                                    <i class="fas fa-minus mr-2"></i>消耗令牌
                                </button>
                            </div>
                        </div>
                        <div class="token-bucket shadow-md">
                            <div id="tokens" class="tokens flex flex-wrap justify-center items-end p-2" style="height: 0%;"></div>
                        </div>
                    </div>
                </div>

                <!-- 1.3 RateLimiter的基本用法 -->
                <div class="mb-12" id="code-example">
                    <h3 class="text-2xl font-semibold text-gray-800 mb-4">1.3 RateLimiter的基本用法</h3>
                    <p class="text-gray-700 mb-6">
                        RateLimiter的API非常简洁：
                    </p>
                    
                    <div class="code-block mb-6">
                        <div class="flex items-center px-4 py-2 border-b border-gray-700">
                            <div class="flex space-x-2">
                                <span class="w-3 h-3 rounded-full bg-red-500"></span>
                                <span class="w-3 h-3 rounded-full bg-yellow-500"></span>
                                <span class="w-3 h-3 rounded-full bg-green-500"></span>
                            </div>
                            <span class="text-gray-400 text-sm ml-2">Java</span>
                        </div>
                        <pre class="p-4 overflow-x-auto text-gray-200"><code>// 创建限流器，每秒允许5个请求
RateLimiter limiter = RateLimiter.create(5.0);

// 阻塞直到获取到令牌
limiter.acquire(); // 获取1个令牌
limiter.acquire(4); // 获取4个令牌

// 非阻塞方式，尝试获取令牌
boolean acquired = limiter.tryAcquire(1, 100, TimeUnit.MILLISECONDS);</code></pre>
                    </div>
                    
                    <p class="text-gray-700">
                        使用起来就是这么简单，但内部实现却很有深度。
                    </p>
                </div>

                <!-- 1.4 RateLimiter的内部实现 -->
                <div class="mb-12">
                    <h3 class="text-2xl font-semibold text-gray-800 mb-4">1.4 RateLimiter的内部实现</h3>
                    <p class="text-gray-700 mb-6">
                        从源码来看，RateLimiter是一个抽象类，有两个具体实现：
                    </p>
                    
                    <div class="flex flex-wrap -mx-4 mb-8">
                        <div class="w-full md:w-1/2 px-4 mb-6">
                            <div class="bg-white p-6 rounded-lg shadow-sm h-full">
                                <h4 class="text-lg font-semibold text-gray-800 mb-3">SmoothBursty</h4>
                                <p class="text-gray-600 mb-4">允许一定程度的突发流量</p>
                                <div class="flex items-center text-sm text-blue-600 mb-2">
                                    <i class="fas fa-bolt mr-2"></i>
                                    <span>适用于常规限流场景</span>
                                </div>
                                <div class="flex items-center text-sm text-green-600 mb-2">
                                    <i class="fas fa-clock mr-2"></i>
                                    <span>立即响应已存储的令牌</span>
                                </div>
                            </div>
                        </div>
                        <div class="w-full md:w-1/2 px-4 mb-6">
                            <div class="bg-white p-6 rounded-lg shadow-sm h-full">
                                <h4 class="text-lg font-semibold text-gray-800 mb-3">SmoothWarmingUp</h4>
                                <p class="text-gray-600 mb-4">带有预热期的平滑限流器</p>
                                <div class="flex items-center text-sm text-purple-600 mb-2">
                                    <i class="fas fa-temperature-low mr-2"></i>
                                    <span>适用于冷启动场景</span>
                                </div>
                                <div class="flex items-center text-sm text-yellow-600 mb-2">
                                    <i class="fas fa-chart-line mr-2"></i>
                                    <span>速率随时间逐渐提升</span>
                                </div>
                            </div>
                        </div>
                    </div>
                    
                    <p class="text-gray-700 mb-4">
                        先看一下RateLimiter的基本架构：
                    </p>
                    
                    <div class="code-block mb-6">
                        <div class="flex items-center px-4 py-2 border-b border-gray-700">
                            <div class="flex space-x-2">
                                <span class="w-3 h-3 rounded-full bg-red-500"></span>
                                <span class="w-3 h-3 rounded-full bg-yellow-500"></span>
                                <span class="w-3 h-3 rounded-full bg-green-500"></span>
                            </div>
                            <span class="text-gray-400 text-sm ml-2">Java</span>
                        </div>
                        <pre class="p-4 overflow-x-auto text-gray-200"><code>// RateLimiter.java (简化版)
public abstract class RateLimiter {
    // 创建一个SmoothBursty实例
    public static RateLimiter create(double permitsPerSecond) {
        return create(permitsPerSecond, SleepingStopwatch.createFromSystemTimer());
    }
    
    // 创建一个SmoothWarmingUp实例
    public static RateLimiter create(double permitsPerSecond, long warmupPeriod, TimeUnit unit) {
        return create(permitsPerSecond, warmupPeriod, unit, 3.0, SleepingStopwatch.createFromSystemTimer());
    }
    
    // 获取令牌，会阻塞直到获取成功
    public double acquire(int permits) {
        long microsToWait = reserve(permits);
        stopwatch.sleepMicrosUninterruptibly(microsToWait);
        return 1.0 * microsToWait / SECONDS.toMicros(1L);
    }
    
    // 尝试获取令牌，有超时控制
    public boolean tryAcquire(int permits, long timeout, TimeUnit unit) {
        long timeoutMicros = unit.toMicros(timeout);
        // 检查等待时间是否超过超时设置
        if (!canAcquire(permits, timeoutMicros)) {
            return false;
        } else {
            return true;
        }
    }
    
    // 核心方法：预留令牌，返回需要等待的时间
    abstract long reserve(int permits);
}</code></pre>
                    </div>
                    
                    <p class="text-gray-700">
                        RateLimiter的工作原理：它不是真的维护一个令牌桶，而是通过计算需要等待的时间来模拟令牌生成的过程。
                    </p>
                </div>
            </section>

            <!-- 2. 平滑限流策略源码分析 -->
            <section class="mb-16">
                <h2 class="text-3xl font-bold text-gray-900 mb-8 section-title">2. 平滑限流策略源码分析</h2>
                
                <!-- 2.1 SmoothRateLimiter基类 -->
                <div class="mb-12">
                    <h3 class="text-2xl font-semibold text-gray-800 mb-4">2.1 SmoothRateLimiter基类</h3>
                    <p class="text-gray-700 mb-6">
                        SmoothRateLimiter是RateLimiter的一个抽象子类，实现了平滑限流的基本逻辑：
                    </p>
                    
                    <div class="code-block mb-6">
                        <div class="flex items-center px-4 py-2 border-b border-gray-700">
                            <div class="flex space-x-2">
                                <span class="w-3 h-3 rounded-full bg-red-500"></span>
                                <span class="w-3 h-3 rounded-full bg-yellow-500"></span>
                                <span class="w-3 h-3 rounded-full bg-green-500"></span>
                            </div>
                            <span class="text-gray-400 text-sm ml-2">Java</span>
                        </div>
                        <pre class="p-4 overflow-x-auto text-gray-200"><code>// SmoothRateLimiter.java (简化版)
abstract class SmoothRateLimiter extends RateLimiter {
    // 当前存储的令牌数
    double storedPermits;
    
    // 最大存储令牌数
    double maxPermits;
    
    // 添加令牌的速率 (令牌/秒)
    double stableIntervalMicros;
    
    // 下一次请求可以获取令牌的时间点
    private long nextFreeTicketMicros;
    
    @Override
    final long reserve(int permits) {
        synchronized (mutex()) {
            return reserveAndGetWaitLength(permits, stopwatch.readMicros());
        }
    }
    
    final long reserveAndGetWaitLength(int permits, long nowMicros) {
        // 可以获取令牌的时间
        long momentAvailable = reserveEarliestAvailable(permits, nowMicros);
        // 需要等待的时间
        return Math.max(momentAvailable - nowMicros, 0);
    }
    
    // 计算获取permits个令牌需要等待的时间
    final long reserveEarliestAvailable(int requiredPermits, long nowMicros) {
        // 重新计算令牌桶中的令牌数
        resync(nowMicros);
        
        // 现在可以获取令牌的时间
        long returnValue = nextFreeTicketMicros;
        
        // 计算需要等待产生的令牌数
        double storedPermitsToSpend = Math.min(requiredPermits, storedPermits);
        double freshPermits = requiredPermits - storedPermitsToSpend;
        
        // 计算等待的时间
        long waitMicros = storedPermitsToWaitTime(storedPermitsToSpend) 
                        + (long) (freshPermits * stableIntervalMicros);
        
        // 更新下一次可以获取令牌的时间
        nextFreeTicketMicros = nextFreeTicketMicros + waitMicros;
        
        // 更新令牌桶中的令牌数
        storedPermits -= storedPermitsToSpend;
        
        return returnValue;
    }
    
    // 重新计算当前存储的令牌数
    void resync(long nowMicros) {
        if (nowMicros > nextFreeTicketMicros) {
            // 计算新产生的令牌数
            double newPermits = (nowMicros - nextFreeTicketMicros) / stableIntervalMicros;
            storedPermits = Math.min(maxPermits, storedPermits + newPermits);
            nextFreeTicketMicros = nowMicros;
        }
    }
    
    // 由子类实现，计算消耗已有令牌所需的等待时间
    abstract double storedPermitsToWaitTime(double storedPermits);
}</code></pre>
                    </div>
                    
                    <p class="text-gray-700">
                        这里的关键是<code class="bg-gray-100 px-1 py-0.5 rounded text-gray-800">resync</code>方法，它根据当前时间和上次请求的时间差，计算新生成的令牌数，并更新令牌桶状态。
                    </p>
                </div>

                <!-- 2.2 SmoothBursty实现分析 -->
                <div class="mb-12">
                    <h3 class="text-2xl font-semibold text-gray-800 mb-4">2.2 SmoothBursty实现分析</h3>
                    <p class="text-gray-700 mb-6">
                        SmoothBursty是最常用的RateLimiter实现，它允许一定程度的突发流量：
                    </p>
                    
                    <div class="code-block mb-6">
                        <div class="flex items-center px-4 py-2 border-b border-gray-700">
                            <div class="flex space-x-2">
                                <span class="w-3 h-3 rounded-full bg-red-500"></span>
                                <span class="w-3 h-3 rounded-full bg-yellow-500"></span>
                                <span class="w-3 h-3 rounded-full bg-green-500"></span>
                            </div>
                            <span class="text-gray-400 text-sm ml-2">Java</span>
                        </div>
                        <pre class="p-4 overflow-x-auto text-gray-200"><code>// SmoothBursty.java (简化版)
static final class SmoothBursty extends SmoothRateLimiter {
    // 最大突发秒数
    final double maxBurstSeconds;
    
    SmoothBursty(SleepingStopwatch stopwatch, double maxBurstSeconds) {
        super(stopwatch);
        this.maxBurstSeconds = maxBurstSeconds;
    }
    
    @Override
    void doSetRate(double permitsPerSecond, double stableIntervalMicros) {
        double oldMaxPermits = maxPermits;
        // 最大存储令牌数 = 每秒令牌数 * 最大突发秒数
        maxPermits = maxBurstSeconds * permitsPerSecond;
        
        // 如果速率改变，需要调整已存储的令牌数
        if (oldMaxPermits == Double.POSITIVE_INFINITY || oldMaxPermits == 0.0) {
            // 如果之前没有限制，则将当前存储的令牌设为最大值的一半
            storedPermits = maxPermits / 2.0;
        } else {
            // 否则，按比例调整
            storedPermits = (oldMaxPermits == 0.0) 
                ? 0.0 
                : storedPermits * maxPermits / oldMaxPermits;
        }
    }
    
    @Override
    double storedPermitsToWaitTime(double storedPermits) {
        // 在SmoothBursty中，消耗已存储的令牌不需要额外等待
        return 0.0;
    }
}</code></pre>
                    </div>
                    
                    <p class="text-gray-700">
                        SmoothBursty的特点是消耗已存储的令牌不需要额外等待时间，这意味着它可以瞬间消耗所有存储的令牌，从而应对突发流量。
                    </p>
                </div>

                <!-- 2.3 SmoothWarmingUp实现分析 -->
                <div class="mb-12">
                    <h3 class="text-2xl font-semibold text-gray-800 mb-4">2.3 SmoothWarmingUp实现分析</h3>
                    <p class="text-gray-700 mb-6">
                        SmoothWarmingUp适用于需要预热的场景，例如冷启动时避免系统瞬间过载：
                    </p>
                    
                    <div class="code-block mb-6">
                        <div class="flex items-center px-4 py-2 border-b border-gray-700">
                            <div class="flex space-x-2">
                                <span class="w-3 h-3 rounded-full bg-red-500"></span>
                                <span class="w-3 h-3 rounded-full bg-yellow-500"></span>
                                <span class="w-3 h-3 rounded-full bg-green-500"></span>
                            </div>
                            <span class="text-gray-400 text-sm ml-2">Java</span>
                        </div>
                        <pre class="p-4 overflow-x-auto text-gray-200"><code>// SmoothWarmingUp.java (简化版)
static final class SmoothWarmingUp extends SmoothRateLimiter {
    // 斜率
    private final double slope;
    // 预热期时长
    private final double warmupPeriodMicros;
    
    SmoothWarmingUp(SleepingStopwatch stopwatch, long warmupPeriod, TimeUnit timeUnit, double coldFactor) {
        super(stopwatch);
        this.warmupPeriodMicros = timeUnit.toMicros(warmupPeriod);
        // coldFactor表示冷启动时的速率降低倍数
        this.slope = coldFactor;
    }
    
    @Override
    void doSetRate(double permitsPerSecond, double stableIntervalMicros) {
        double oldMaxPermits = maxPermits;
        // 计算预热期需要的令牌数
        double warmupPermits = permitsPerSecond * warmupPeriodMicros / 1000000.0;
        // 一半的令牌用于预热
        maxPermits = warmupPermits;
        
        // 调整已存储的令牌数
        // ...类似SmoothBursty的逻辑
    }
    
    @Override
    double storedPermitsToWaitTime(double storedPermits) {
        // 这里的计算比较复杂，涉及积分和斜率
        // 基本思想是：令牌越少，获取单个令牌的等待时间越接近正常速率
        // 令牌越多（越接近预热状态），获取单个令牌的等待时间越长
        
        // 计算曲线下方的面积，作为等待时间
        double availablePermitsAboveThreshold = storedPermits - thresholdPermits;
        long waitMicros;
        
        if (availablePermitsAboveThreshold > 0.0) {
            double permitsAboveThresholdMicros = availablePermitsAboveThreshold * stableIntervalMicros;
            waitMicros = (long) (permitsAboveThresholdMicros * (1.0 + slope) / 2.0);
        } else {
            waitMicros = 0;
        }
        
        return waitMicros;
    }
}</code></pre>
                    </div>
                    
                    <p class="text-gray-700">
                        SmoothWarmingUp的核心是<code class="bg-gray-100 px-1 py-0.5 rounded text-gray-800">storedPermitsToWaitTime</code>方法，它使得系统在冷启动时速率较低，随着时间推移逐渐恢复到正常速率。
                    </p>
                </div>
            </section>

            <!-- 3. 时间窗口计算与令牌分配机制 -->
            <section class="mb-16">
                <h2 class="text-3xl font-bold text-gray-900 mb-8 section-title">3. 时间窗口计算与令牌分配机制</h2>
                
                <!-- 3.1 时间窗口的设计 -->
                <div class="mb-12">
                    <h3 class="text-2xl font-semibold text-gray-800 mb-4">3.1 时间窗口的设计</h3>
                    <p class="text-gray-700 mb-6">
                        RateLimiter不使用固定的时间窗口，而是采用滑动窗口的思想：
                    </p>
                    
                    <div class="code-block mb-6">
                        <div class="flex items-center px-4 py-2 border-b border-gray-700">
                            <div class="flex space-x-2">
                                <span class="w-3 h-3 rounded-full bg-red-500"></span>
                                <span class="w-3 h-3 rounded-full bg-yellow-500"></span>
                                <span class="w-3 h-3 rounded-full bg-green-500"></span>
                            </div>
                            <span class="text-gray-400 text-sm ml-2">Java</span>
                        </div>
                        <pre class="p-4 overflow-x-auto text-gray-200"><code>void resync(long nowMicros) {
    if (nowMicros > nextFreeTicketMicros) {
        // 计算新产生的令牌数
        double newPermits = (nowMicros - nextFreeTicketMicros) / stableIntervalMicros;
        storedPermits = Math.min(maxPermits, storedPermits + newPermits);
        nextFreeTicketMicros = nowMicros;
    }
}</code></pre>
                    </div>
                    
                    <p class="text-gray-700">
                        这种设计的优点是避免了固定时间窗口带来的边界问题。例如，在固定1秒的窗口中，可能前500ms没有请求，而后500ms突然来了大量请求，导致系统不堪重负。
                    </p>
                    <p class="text-gray-700">
                        RateLimiter的滑动窗口实现让限流更加平滑，避免了这种问题。
                    </p>
                </div>

                <!-- 3.2 令牌生成与分配策略 -->
                <div class="mb-12">
                    <h3 class="text-2xl font-semibold text-gray-800 mb-4">3.2 令牌生成与分配策略</h3>
                    <p class="text-gray-700 mb-6">
                        RateLimiter的令牌生成策略很有趣：它并不是定时生成令牌，而是在请求到来时，根据上次请求的时间差，按需计算应该生成多少令牌。
                    </p>
                    <p class="text-gray-700 mb-6">
                        这种"懒加载"的设计非常高效，避免了不必要的计时器调度和空闲检查。
                    </p>
                    <p class="text-gray-700 mb-6">
                        令牌分配策略也很灵活：
                    </p>
                    <ol class="list-decimal pl-6 mb-6 text-gray-700 space-y-2">
                        <li><strong>请求量小于等于已存储令牌时</strong>：立即消耗已存储的令牌，无需等待</li>
                        <li><strong>请求量大于已存储令牌时</strong>：先消耗所有已存储的令牌，然后计算需要等待多长时间才能获取剩余的令牌</li>
                    </ol>
                    <p class="text-gray-700">
                        这种策略既允许处理突发流量，又能保证长期平均速率不超过限制。
                    </p>
                </div>

                <!-- 3.3 动态调整限流速率 -->
                <div class="mb-12">
                    <h3 class="text-2xl font-semibold text-gray-800 mb-4">3.3 动态调整限流速率</h3>
                    <p class="text-gray-700 mb-6">
                        RateLimiter支持动态调整限流速率：
                    </p>
                    
                    <div class="code-block mb-6">
                        <div class="flex items-center px-4 py-2 border-b border-gray-700">
                            <div class="flex space-x-2">
                                <span class="w-3 h-3 rounded-full bg-red-500"></span>
                                <span class="w-3 h-3 rounded-full bg-yellow-500"></span>
                                <span class="w-3 h-3 rounded-full bg-green-500"></span>
                            </div>
                            <span class="text-gray-400 text-sm ml-2">Java</span>
                        </div>
                        <pre class="p-4 overflow-x-auto text-gray-200"><code>// 创建限流器，初始速率为5请求/秒
RateLimiter limiter = RateLimiter.create(5.0);

// 某些条件下，动态调整为10请求/秒
limiter.setRate(10.0);</code></pre>
                    </div>
                    
                    <p class="text-gray-700 mb-6">
                        源码中对速率调整的处理很有深度：
                    </p>
                    
                    <div class="code-block mb-6">
                        <div class="flex items-center px-4 py-2 border-b border-gray-700">
                            <div class="flex space-x-2">
                                <span class="w-3 h-3 rounded-full bg-red-500"></span>
                                <span class="w-3 h-3 rounded-full bg-yellow-500"></span>
                                <span class="w-3 h-3 rounded-full bg-green-500"></span>
                            </div>
                            <span class="text-gray-400 text-sm ml-2">Java</span>
                        </div>
                        <pre class="p-4 overflow-x-auto text-gray-200"><code>public final void setRate(double permitsPerSecond) {
    checkArgument(permitsPerSecond > 0.0 && !Double.isNaN(permitsPerSecond), "rate must be positive");
    synchronized (mutex()) {
        doSetRate(permitsPerSecond, stopwatch.readMicros());
    }
}

void doSetRate(double permitsPerSecond, long nowMicros) {
    // 重新同步令牌状态
    resync(nowMicros);
    
    // 计算新的时间间隔
    double stableIntervalMicros = SECONDS.toMicros(1L) / permitsPerSecond;
    this.stableIntervalMicros = stableIntervalMicros;
    
    // 子类特定的速率调整逻辑
    doSetRate(permitsPerSecond, stableIntervalMicros);
}</code></pre>
                    </div>
                    
                    <p class="text-gray-700">
                        当调整速率时，RateLimiter会尽量保持公平，按比例调整已存储的令牌数。
                    </p>
                </div>
            </section>

            <!-- 4. API限流保护 -->
            <section class="mb-16">
                <h2 class="text-3xl font-bold text-gray-900 mb-8 section-title">4. API限流保护</h2>
                <p class="text-gray-700 mb-6">
                    在我的实际工作中，RateLimiter帮我解决了不少问题。下面分享一个典型的API限流保护案例：
                </p>
                
                <div class="code-block mb-6">
                    <div class="flex items-center px-4 py-2 border-b border-gray-700">
                        <div class="flex space-x-2">
                            <span class="w-3 h-3 rounded-full bg-red-500"></span>
                            <span class="w-3 h-3 rounded-full bg-yellow-500"></span>
                            <span class="w-3 h-3 rounded-full bg-green-500"></span>
                        </div>
                        <span class="text-gray-400 text-sm ml-2">Java</span>
                    </div>
                    <pre class="p-4 overflow-x-auto text-gray-200"><code>public class RateLimitedApiService {
    // 全局限流器，限制总体QPS
    private final RateLimiter globalLimiter;
    
    // 用户级别限流器，防止单个用户占用过多资源
    private final LoadingCache&lt;String, RateLimiter&gt; userLimiters;
    
    // 底层API客户端
    private final ApiClient apiClient;
    
    public RateLimitedApiService(ApiClient apiClient, int globalQps, int perUserQps) {
        this.apiClient = apiClient;
        this.globalLimiter = RateLimiter.create(globalQps);
        
        // 为每个用户创建独立的限流器
        this.userLimiters = CacheBuilder.newBuilder()
            .expireAfterAccess(10, TimeUnit.MINUTES) // 10分钟不活跃则移除
            .build(new CacheLoader&lt;String, RateLimiter&gt;() {
                @Override
                public RateLimiter load(String userId) {
                    return RateLimiter.create(perUserQps);
                }
            });
    }
    
    public ApiResponse callApi(String userId, ApiRequest request) throws ApiException {
        // 首先尝试获取全局令牌
        if (!globalLimiter.tryAcquire(1, 100, TimeUnit.MILLISECONDS)) {
            throw new ApiException("系统繁忙，请稍后再试");
        }
        
        // 然后检查用户级别限流
        RateLimiter userLimiter;
        try {
            userLimiter = userLimiters.get(userId);
        } catch (ExecutionException e) {
            throw new ApiException("获取用户限流器失败", e);
        }
        
        // 尝试获取用户级别令牌
        if (!userLimiter.tryAcquire(1, 50, TimeUnit.MILLISECONDS)) {
            throw new ApiException("您的请求过于频繁，请稍后再试");
        }
        
        // 通过限流检查，调用实际API
        return apiClient.call(request);
    }
    
    // 动态调整限流参数
    public void updateRateLimit(int newGlobalQps, int newPerUserQps) {
        globalLimiter.setRate(newGlobalQps);
        
        // 更新所有用户的限流器
        for (RateLimiter limiter : userLimiters.asMap().values()) {
            limiter.setRate(newPerUserQps);
        }
    }
}</code></pre>
                </div>
                
                <p class="text-gray-700 mb-6">
                    这个实现解决了几个实际问题：
                </p>
                <ul class="list-disc pl-6 mb-6 text-gray-700 space-y-2">
                    <li><strong>全局流量控制</strong>：防止系统整体过载</li>
                    <li><strong>用户级别隔离</strong>：防止单个用户抢占所有资源</li>
                    <li><strong>优雅降级</strong>：在流量超限时返回友好错误，而不是简单地阻塞</li>
                    <li><strong>动态调整</strong>：根据系统负载动态调整限流参数</li>
                </ul>
                <p class="text-gray-700 mb-6">
                    在生产环境中，这个方案帮我们抵御了多次流量高峰，系统始终保持稳定。尤其是在一次营销活动中，正是它拯救了本来可能会崩溃的系统。
                </p>

                <!-- 4.1 限流日志和监控 -->
                <div class="mb-12">
                    <h3 class="text-2xl font-semibold text-gray-800 mb-4">4.1 限流日志和监控</h3>
                    <p class="text-gray-700 mb-6">
                        在实际应用中，限流不仅仅是为了保护系统，还需要提供可观测性。我们可以扩展上面的例子，添加监控功能：
                    </p>
                    
                    <div class="code-block mb-6">
                        <div class="flex items-center px-4 py-2 border-b border-gray-700">
                            <div class="flex space-x-2">
                                <span class="w-3 h-3 rounded-full bg-red-500"></span>
                                <span class="w-3 h-3 rounded-full bg-yellow-500"></span>
                                <span class="w-3 h-3 rounded-full bg-green-500"></span>
                            </div>
                            <span class="text-gray-400 text-sm ml-2">Java</span>
                        </div>
                        <pre class="p-4 overflow-x-auto text-gray-200"><code>public ApiResponse callApi(String userId, ApiRequest request) throws ApiException {
    // 记录全局限流情况
    boolean globalLimited = false;
    long startTime = System.nanoTime();
    double waitTime = 0;
    
    if (!globalLimiter.tryAcquire(1, 100, TimeUnit.MILLISECONDS)) {
        globalLimited = true;
        throttleMetrics.incrementGlobalThrottleCount();
        throw new ApiException("系统繁忙，请稍后再试");
    }
    
    // 用户级别限流统计
    boolean userLimited = false;
    RateLimiter userLimiter;
    try {
        userLimiter = userLimiters.get(userId);
        if (!userLimiter.tryAcquire(1, 50, TimeUnit.MILLISECONDS)) {
            userLimited = true;
            throttleMetrics.incrementUserThrottleCount(userId);
            throw new ApiException("您的请求过于频繁，请稍后再试");
        }
        
        // 计算等待时间
        waitTime = (System.nanoTime() - startTime) / 1_000_000.0;
        
        // 记录等待时间指标
        throttleMetrics.recordWaitTime(waitTime);
        
        // 通过限流检查，调用实际API
        return apiClient.call(request);
    } catch (ExecutionException e) {
        throw new ApiException("获取用户限流器失败", e);
    } finally {
        // 记录限流日志
        if (globalLimited || userLimited) {
            log.warn("API请求被限流 - 用户:{}, 全局限流:{}, 用户限流:{}, 等待时间:{}ms",
                    userId, globalLimited, userLimited, waitTime);
        }
    }
}</code></pre>
                    </div>
                    
                    <p class="text-gray-700 mb-6">
                        通过这些监控指标，我们可以：
                    </p>
                    <ul class="list-disc pl-6 mb-6 text-gray-700 space-y-2">
                        <li>了解系统当前的限流情况</li>
                        <li>识别频繁触发限流的用户</li>
                        <li>根据限流趋势调整系统容量</li>
                        <li>评估限流策略的有效性</li>
                    </ul>
                </div>
            </section>

            <!-- 5. RateLimiter的性能与优化 -->
            <section class="mb-16">
                <h2 class="text-3xl font-bold text-gray-900 mb-8 section-title">5. RateLimiter的性能与优化</h2>
                
                <!-- 5.1 性能特性分析 -->
                <div class="mb-12">
                    <h3 class="text-2xl font-semibold text-gray-800 mb-4">5.1 性能特性分析</h3>
                    <p class="text-gray-700 mb-6">
                        RateLimiter的性能特性值得称赞：
                    </p>
                    <ul class="list-disc pl-6 mb-6 text-gray-700 space-y-2">
                        <li><strong>低开销</strong>：核心操作只涉及几个简单的算术计算和同步块</li>
                        <li><strong>无锁等待</strong>：使用的是System.nanoTime()和Thread.sleep()，不依赖锁</li>
                        <li><strong>惰性计算</strong>：只在需要时才计算令牌生成，避免定时器调度</li>
                    </ul>
                    <p class="text-gray-700 mb-6">
                        在我的基准测试中，单个RateLimiter实例在高并发下的表现相当出色：
                    </p>
                    <ul class="list-disc pl-6 mb-6 text-gray-700 space-y-2">
                        <li>每次acquire()调用平均只需约0.5微秒（不包括限流导致的休眠时间）</li>
                        <li>即使在100个线程并发访问的情况下，性能下降也不超过20%</li>
                    </ul>
                </div>

                <!-- 5.2 与其他限流方案的对比 -->
                <div class="mb-12">
                    <h3 class="text-2xl font-semibold text-gray-800 mb-4">5.2 与其他限流方案的对比</h3>
                    <p class="text-gray-700 mb-6">
                        与其他常见的限流方案相比，RateLimiter各有优缺点：
                    </p>
                    
                    <div class="overflow-x-auto">
                        <table class="compare-table min-w-full bg-white rounded-lg overflow-hidden mb-6">
                            <thead>
                                <tr class="text-left">
                                    <th class="py-3 px-4">方案</th>
                                    <th class="py-3 px-4">优点</th>
                                    <th class="py-3 px-4">缺点</th>
                                </tr>
                            </thead>
                            <tbody>
                                <tr>
                                    <td class="py-3 px-4 font-medium">RateLimiter</td>
                                    <td class="py-3 px-4">简单易用，性能高，支持平滑限流</td>
                                    <td class="py-3 px-4">只支持单机，不支持集群</td>
                                </tr>
                                <tr>
                                    <td class="py-3 px-4 font-medium">Redis+Lua</td>
                                    <td class="py-3 px-4">支持分布式，精确控制</td>
                                    <td class="py-3 px-4">需要额外的Redis依赖，有网络开销</td>
                                </tr>
                                <tr>
                                    <td class="py-3 px-4 font-medium">Sentinel</td>
                                    <td class="py-3 px-4">功能全面，支持多种限流策略</td>
                                    <td class="py-3 px-4">较为复杂，学习成本高</td>
                                </tr>
                            </tbody>
                        </table>
                    </div>
                    
                    <p class="text-gray-700">
                        在我看来，如果是单机服务，RateLimiter无疑是首选；如果是分布式系统，则需要考虑Redis或专业的限流组件。
                    </p>
                </div>

                <!-- 5.3 实际应用中的优化建议 -->
                <div class="mb-12">
                    <h3 class="text-2xl font-semibold text-gray-800 mb-4">5.3 实际应用中的优化建议</h3>
                    <p class="text-gray-700 mb-6">
                        基于我的实践经验，这里有一些使用RateLimiter的优化建议：
                    </p>
                    <ul class="list-disc pl-6 mb-6 text-gray-700 space-y-2">
                        <li><strong>合理设置预热期</strong>：根据系统特性设置合适的预热期，避免冷启动问题</li>
                        <li><strong>分级限流</strong>：实现多级限流策略，如API级别、用户级别和IP级别</li>
                        <li><strong>结合熔断</strong>：限流与熔断结合使用，提供更全面的保护</li>
                        <li><strong>动态调整</strong>：根据系统负载动态调整限流参数</li>
                    </ul>
                    
                    <div class="code-block mb-6">
                        <div class="flex items-center px-4 py-2 border-b border-gray-700">
                            <div class="flex space-x-2">
                                <span class="w-3 h-3 rounded-full bg-red-500"></span>
                                <span class="w-3 h-3 rounded-full bg-yellow-500"></span>
                                <span class="w-3 h-3 rounded-full bg-green-500"></span>
                            </div>
                            <span class="text-gray-400 text-sm ml-2">Java</span>
                        </div>
                        <pre class="p-4 overflow-x-auto text-gray-200"><code>// 优化示例：结合熔断的限流器
public class CircuitBreakingRateLimiter {
    private final RateLimiter rateLimiter;
    private final AtomicInteger failureCount = new AtomicInteger(0);
    private final AtomicBoolean circuitOpen = new AtomicBoolean(false);
    private final int failureThreshold;
    private volatile long resetTime;
    
    public CircuitBreakingRateLimiter(double permitsPerSecond, int failureThreshold) {
        this.rateLimiter = RateLimiter.create(permitsPerSecond);
        this.failureThreshold = failureThreshold;
    }
    
    public boolean tryAcquire() {
        // 检查断路器是否打开
        if (circuitOpen.get()) {
            if (System.currentTimeMillis() > resetTime) {
                // 重置断路器
                circuitOpen.set(false);
                failureCount.set(0);
            } else {
                return false;
            }
        }
        
        // 尝试获取令牌
        return rateLimiter.tryAcquire();
    }
    
    public void recordFailure() {
        int failures = failureCount.incrementAndGet();
        if (failures >= failureThreshold) {
            // 打开断路器
            circuitOpen.set(true);
            // 设置重置时间
            resetTime = System.currentTimeMillis() + 30000; // 30秒后重置
        }
    }
    
    public void recordSuccess() {
        // 成功时减少失败计数
        failureCount.updateAndGet(count -> Math.max(0, count - 1));
    }
}</code></pre>
                    </div>
                    
                    <p class="text-gray-700">
                        这种组合设计不仅限制了请求速率，还能在系统出现异常时快速切断流量，提供双重保护。
                    </p>
                </div>
            </section>

            <!-- Conclusion -->
            <section class="mb-16">
                <div class="bg-gradient-to-r from-blue-50 to-blue-100 p-8 rounded-xl border border-blue-200">
                    <div class="flex items-center mb-6">
                        <div class="h-px bg-gradient-to-r from-blue-400 to-transparent w-16"></div>
                        <span class="text-blue-600 font-medium ml-4">总结</span>
                    </div>
                    <h2 class="text-3xl font-bold text-gray-900 mb-6">RateLimiter 的价值与应用</h2>
                    <p class="text-gray-700 mb-6 leading-relaxed">
                        Guava的RateLimiter是一个设计精巧、性能优异的限流工具，它基于令牌桶算法实现，提供了简单而强大的API。通过本文的分析，我们深入了解了它的内部实现原理，包括SmoothBursty和SmoothWarmingUp两种实现策略，以及它们在处理突发流量和冷启动问题上的不同表现。
                    </p>
                    <p class="text-gray-700 mb-6 leading-relaxed">
                        在实际应用中，合理使用RateLimiter可以帮助我们构建更加健壮的高并发系统，防止系统过载、避免连锁故障、平滑业务流量峰值，以及防御恶意攻击。通过多级限流、动态调整和监控告警等优化手段，我们可以充分发挥RateLimiter的潜力，为业务保驾护航。
                    </p>
                    <div class="flex items-center text-blue-600">
                        <i class="fas fa-lightbulb mr-2"></i>
                        <span>记住：在高并发系统中，限流不是可选项，而是必选项！</span>
                    </div>
                </div>
            </section>
        </article>
    </main>

    <!-- Footer -->
    <footer class="bg-gray-900 text-gray-300 py-8 px-4">
        <div class="max-w-6xl mx-auto flex flex-col md:flex-row justify-between items-center">
            <div class="mb-4 md:mb-0">
                <h3 class="text-xl font-semibold text-white mb-2">技术小馆</h3>
                <p class="text-gray-400">深入技术细节，品味编程艺术</p>
            </div>
            <div>
                <a href="http://www.yuque.com/jtostring" class="text-blue-400 hover:text-blue-300 transition duration-200">
                    <i class="fas fa-globe mr-2"></i>http://www.yuque.com/jtostring
                </a>
            </div>
        </div>
    </footer>

    <script>
        // Token Bucket Visualization
        document.addEventListener('DOMContentLoaded', function() {
            const tokenBucket = document.getElementById('tokens');
            const addTokenBtn = document.getElementById('addTokenBtn');
            const consumeTokenBtn = document.getElementById('consumeTokenBtn');
            
            let tokenCount = 0;
            const maxTokens = 20;
            
            function updateTokenDisplay() {
                const percentage = Math.min(tokenCount / maxTokens * 100, 100);
                tokenBucket.style.height = `${percentage}%`;
                
                // Update token dots
                tokenBucket.innerHTML = '';
                const tokensToShow = Math.min(tokenCount, 20); // Max 20 dots to prevent overflow
                for (let i = 0; i < tokensToShow; i++) {
                    const token = document.createElement('div');
                    token.className = 'token';
                    tokenBucket.appendChild(token);
                }
            }
            
            addTokenBtn.addEventListener('click', function() {
                if (tokenCount < maxTokens) {
                    tokenCount += 5;
                    updateTokenDisplay();
                }
            });
            
            consumeTokenBtn.addEventListener('click', function() {
                if (tokenCount >= 5) {
                    tokenCount -= 5;
                    updateTokenDisplay();
                }
            });
            
            // Initial display
            updateTokenDisplay();
        });
    </script>
</body>
</html>
```